package com.ruifu.act.contorller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fhzncloud.cloud.common.core.util.PageR;
import com.fhzncloud.cloud.common.core.util.R;
import com.fhzncloud.cloud.common.security.annotation.Inner;
import com.fhzncloud.cloud.common.security.service.CloudUser;
import com.fhzncloud.cloud.common.security.util.SecurityUtils;
import com.ruifu.act.dto.ModelDto;
import com.ruifu.act.service.ImageService;
import com.ruifu.act.service.ProcessActService;
import com.ruifu.act.service.ProcessModelService;
import com.ruifu.act.vo.ProcessDefinitionVO;
import com.ruifu.common.vo.ResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;


/**
 * 流程部署相关请求方法Controller
 *
 * @author lcq
 * @create 2019/11/20
 */
@Slf4j
@RestController
@CrossOrigin
@RequestMapping("/model")
@Api(tags = "流程模版相关Controller")
public class ModelController {

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    private ProcessModelService processModelService;

    @Autowired
    private ProcessActService processActService;

    @Autowired
    private ImageService imageService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 用于存储登陆人信息
     */
    private CloudUser cloudUser;

    /**
     * 通过url请求方法之前,调用该方法获取登陆人信息
     */
    @ModelAttribute
    public void before() {
        cloudUser = SecurityUtils.getUser();
    }


    /**
     * 查询指定条件下，该账号账套下对应的模型是否存在
     *
     * @param modelName
     * @param modelKey
     * @return
     */
    @GetMapping("/isModelExist")
    @ApiOperation(value = "查询指定条件下，该账号账套下对应的模型是否存在", notes = "判断名称或者模板key是否重复")
    public R<Boolean> verifyModelIsExist(@RequestParam(value = "name", required = false) String modelName,
                                         @RequestParam(value = "key", required = false) String modelKey) {
        return this.processModelService.verifyModelIsExist(modelName, modelKey, cloudUser.getTenantId().toString());
    }

    /**
     * 创建流程模板
     *
     * @param modelDto
     * @return
     * @throws IOException
     */
    @PostMapping("/create")
    @ApiOperation(value = "创建流程模板", notes = "传入参数为构造的参数，具体值可以点击查看")
    public String create(@RequestBody ModelDto modelDto, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String id = "";

        if (null != cloudUser.getTenantId()) {
            id = this.processModelService.initEmptyModel(modelDto, cloudUser.getTenantId().toString());

            if (null != id) {
                return "/modeler.html?modelId=" + id;
            }
        }

        return null;
    }

    /**
     * 编辑流程模板
     *
     * @param modelId
     * @return
     */
    @GetMapping("/editor/{modelId}")
    @ApiOperation(value = "编辑流程模板", notes = "返回对应的页面URI信息")
    public String editor(@PathVariable("modelId") String modelId) {
        return "/modeler.html?modelId=" + modelId;
    }

    /**
     * 部署流程模板
     *
     * @param modelId
     * @return
     * @throws IOException
     */
    @GetMapping("/deploy/{modelId}")
    @ApiOperation(value = "部署流程模板", notes = "根据对应的modelId启动相应的模板流程")
    public R deploy(@PathVariable("modelId") String modelId) throws IOException {
        return this.processModelService.deployModel(modelId);
    }

    /**
     * 根据账套id查询模板列表
     */
    @GetMapping("/QueryModelListByTenantId/{page}/{size}")
    @ApiOperation(value = "根据账套id查询模板列表", notes = "分页查询模板列表")
    public PageR<List<Model>> modelList(@PathVariable("page") Integer page,
                                        @PathVariable("size") Integer size) {
        //log.info(cloudUser.getTenantId().toString());
        Integer pageNum = page == null ? 1 : page;
        Integer sizeNum = page == null ? 10 : size;
        return processModelService.queryModelListByTenantId(cloudUser.getTenantId().toString(), pageNum, sizeNum);
    }

    /**
     * 导出模板(xml)
     *
     * @param request
     * @param response
     * @param modelId
     */
    @GetMapping(value = "export/{modelId}")
    @ApiOperation(value = "导出模板(xml)", notes = "根据对应的modelId，导出对应的xml")
    public void export(HttpServletRequest request, HttpServletResponse response, @PathVariable String modelId) {
        this.processModelService.exportModelToXml(request, response, modelId);
    }

    /**
     * 批量删除流程模板
     *
     * @param modelIdList
     * @return
     */
    @PostMapping("/deleteModel")
    @ApiOperation(value = "批量删除流程模板", notes = "传入参数为modelId集合")
    public ResultVO deleteModel(@RequestBody List<String> modelIdList) {
        try {
            if (modelIdList.size() > 0) {
                for (String modelId : modelIdList) {
                    repositoryService.deleteModel(modelId);
                }
            }
            return new ResultVO(true, "模板删除成功");
        } catch (Exception e) {
            log.error("模板删除失败", e);
            return new ResultVO(false, "模板删除失败");
        }

    }

    /**
     * 根据账套id查询流程定义列表
     */
    @GetMapping("/QueryProcessDefinitionByTenantId/{page}/{size}")
    @ApiOperation(value = "根据账套id查询流程定义列表", notes = "分页查询流程定义列表")
    public PageR<List<ProcessDefinitionVO>> processDefinitionList(@PathVariable("page") Integer page,
                                                                  @PathVariable("size") Integer size) {
        Integer pageNum = page == null ? 1 : page;
        Integer sizeNum = page == null ? 10 : size;
        return processModelService.queryProcessDefinitionByTenantId(cloudUser.getTenantId().toString(), pageNum, sizeNum);
    }

    /**
     * 挂起流程定义suspended
     *
     * @param processDefinitionId
     * @return
     */
    @GetMapping("/suspendProcessDefinitionId/{processDefinitionId}")
    @ApiOperation(value = "挂起流程定义suspended", notes = "根据流程定义id，挂起对应的部署流程")
    public ResultVO suspendProcessInstance(@PathVariable("processDefinitionId") String processDefinitionId) {
        try {
            //当流程定义被挂起时，已经发起的该流程定义的流程实例不受影响.如果选择级联挂起则正在跑的流程实例也会被挂起
            repositoryService.suspendProcessDefinitionById(processDefinitionId);
            return new ResultVO(true, "挂起成功");
        } catch (Exception e) {
            log.error("挂起失败", e);
            return new ResultVO(false, "挂起失败");
        }
    }

    /**
     * 激活流程定义activation
     *
     * @param processDefinitionId
     * @return
     */
    @GetMapping("/activateProcessDefinitionId/{processDefinitionId}")
    @ApiOperation(value = "激活流程定义activation", notes = "根据流程定义id，激活对应的部署流程")
    public ResultVO activateProcessInstance(@PathVariable("processDefinitionId") String processDefinitionId) {
        try {
            repositoryService.activateProcessDefinitionById(processDefinitionId);
            return new ResultVO(true, "激活成功");
        } catch (Exception e) {
            log.error("激活失败", e);
            return new ResultVO(false, "激活失败");
        }
    }

    /**
     * 批量删除key值相同的所有版本的流程定义
     */
    @PostMapping("/deleteDeploy")
    @ApiOperation(value = "删除流程定义", notes = "批量删除key值相同的所有版本的流程定义")
    public ResultVO deleteProcessDefinition(@RequestBody List<String> processDefinitionKeyList) {
        return processModelService.deleteProcessDefinition(processDefinitionKeyList);
    }

    /**
     * 获取流程图像，已执行节点和流程线高亮显示
     *
     * @param procInstId
     * @param response
     * @return
     * @throws Exception
     */
    @GetMapping(value = "processImage/{procInstId}")
    @ApiOperation(value = "获取流程图像", notes = "获取流程图像，已执行节点和流程线高亮显示")
    public void processImage(@PathVariable("procInstId") String procInstId, HttpServletResponse response) {
        try (OutputStream out = response.getOutputStream();
             InputStream is = imageService.getFlowImgByProcInstId(null, procInstId, true)) {
            if (null != is) {
                BufferedImage image = ImageIO.read(is);

                response.setContentType("image/png");
                ImageIO.write(image, "png", out);
            }
        } catch (Exception ex) {
            log.error("查看流程图失败", ex);
        }
    }

    /**
     * 从默认账套的模板数据中拷贝模板信息到新的账套(内部方法)
     *
     * @param sourceTenantId
     * @param targetTenantId
     * @return
     */
    @GetMapping(value = "tenantTemplateCopy/{sourceTenantId}/{targetTenantId}")
    @Inner
    public Boolean tenantTemplateCopy(@PathVariable("sourceTenantId") Integer sourceTenantId,
                                      @PathVariable("targetTenantId") Integer targetTenantId) {
        return this.processModelService.tenantTemplateCopy(sourceTenantId, targetTenantId);
    }

}